package org.codehaus.activemq.message;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.MessageFormatException;
import javax.jms.MessageNotWriteableException;

public class ActiveMQMapMessage extends ActiveMQMessage
  implements MapMessage
{
  private Hashtable theTable;

  public int getPacketType()
  {
    return 11;
  }

  public ActiveMQMessage shallowCopy()
    throws JMSException
  {
    ActiveMQMapMessage other = new ActiveMQMapMessage();
    initializeOther(other);
    other.theTable = this.theTable;
    return other;
  }

  public ActiveMQMessage deepCopy()
    throws JMSException
  {
    ActiveMQMapMessage other = new ActiveMQMapMessage();
    initializeOther(other);
    if (this.theTable != null) {
      other.theTable = ((Hashtable)this.theTable.clone());
    }
    return other;
  }

  public void setTable(Hashtable newTable)
  {
    this.theTable = newTable;
  }

  public Hashtable getTable()
    throws JMSException
  {
    if (this.theTable == null) {
      try {
        super.buildBodyFromBytes();
      }
      catch (IOException ioe) {
        JMSException jmsEx = new JMSException("building table from data failed");
        jmsEx.setLinkedException(ioe);
        throw jmsEx;
      }
    }
    if (this.theTable == null) {
      this.theTable = new Hashtable();
    }
    return this.theTable;
  }

  public void clearBody()
    throws JMSException
  {
    super.clearBody();
    getTable().clear();
  }

  public boolean getBoolean(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return false;
    }
    if ((value instanceof Boolean)) {
      return ((Boolean)value).booleanValue();
    }
    if ((value instanceof String)) {
      return Boolean.valueOf(value.toString()).booleanValue();
    }

    throw new MessageFormatException(" cannot read a boolean from " + value.getClass().getName());
  }

  public byte getByte(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return 0;
    }
    if ((value instanceof Byte)) {
      return ((Byte)value).byteValue();
    }
    if ((value instanceof String)) {
      return Byte.valueOf(value.toString()).byteValue();
    }

    throw new MessageFormatException(" cannot read a byte from " + value.getClass().getName());
  }

  public short getShort(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return 0;
    }
    if ((value instanceof Short)) {
      return ((Short)value).shortValue();
    }
    if ((value instanceof Byte)) {
      return ((Byte)value).shortValue();
    }
    if ((value instanceof String)) {
      return Short.valueOf(value.toString()).shortValue();
    }

    throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
  }

  public char getChar(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      throw new NullPointerException();
    }
    if ((value instanceof Character)) {
      return ((Character)value).charValue();
    }

    throw new MessageFormatException(" cannot read a short from " + value.getClass().getName());
  }

  public int getInt(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return 0;
    }
    if ((value instanceof Integer)) {
      return ((Integer)value).intValue();
    }
    if ((value instanceof Short)) {
      return ((Short)value).intValue();
    }
    if ((value instanceof Byte)) {
      return ((Byte)value).intValue();
    }
    if ((value instanceof String)) {
      return Integer.valueOf(value.toString()).intValue();
    }

    throw new MessageFormatException(" cannot read an int from " + value.getClass().getName());
  }

  public long getLong(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return 0L;
    }
    if ((value instanceof Long)) {
      return ((Long)value).longValue();
    }
    if ((value instanceof Integer)) {
      return ((Integer)value).longValue();
    }
    if ((value instanceof Short)) {
      return ((Short)value).longValue();
    }
    if ((value instanceof Byte)) {
      return ((Byte)value).longValue();
    }
    if ((value instanceof String)) {
      return Long.valueOf(value.toString()).longValue();
    }

    throw new MessageFormatException(" cannot read a long from " + value.getClass().getName());
  }

  public float getFloat(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return 0.0F;
    }
    if ((value instanceof Float)) {
      return ((Float)value).floatValue();
    }
    if ((value instanceof String)) {
      return Float.valueOf(value.toString()).floatValue();
    }

    throw new MessageFormatException(" cannot read a float from " + value.getClass().getName());
  }

  public double getDouble(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return 0.0D;
    }
    if ((value instanceof Double)) {
      return ((Double)value).doubleValue();
    }
    if ((value instanceof Float)) {
      return ((Float)value).floatValue();
    }
    if ((value instanceof String)) {
      return Float.valueOf(value.toString()).floatValue();
    }

    throw new MessageFormatException(" cannot read a double from " + value.getClass().getName());
  }

  public String getString(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if (value == null) {
      return null;
    }
    if ((value instanceof byte[])) {
      throw new MessageFormatException("Use getBytes to read a byte array");
    }

    return value.toString();
  }

  public byte[] getBytes(String name)
    throws JMSException
  {
    Object value = getTable().get(name);
    if ((value instanceof byte[])) {
      return (byte[])value;
    }

    throw new MessageFormatException(" cannot read a byte[] from " + value.getClass().getName());
  }

  public Object getObject(String name)
    throws JMSException
  {
    return getTable().get(name);
  }

  public Enumeration getMapNames()
    throws JMSException
  {
    return getTable().keys();
  }

  public void setBoolean(String name, boolean value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, value ? Boolean.TRUE : Boolean.FALSE);
  }

  public void setByte(String name, byte value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, new Byte(value));
  }

  public void setShort(String name, short value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, new Short(value));
  }

  public void setChar(String name, char value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, new Character(value));
  }

  public void setInt(String name, int value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, new Integer(value));
  }

  public void setLong(String name, long value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, new Long(value));
  }

  public void setFloat(String name, float value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, new Float(value));
  }

  public void setDouble(String name, double value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, new Double(value));
  }

  public void setString(String name, String value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, value);
  }

  public void setBytes(String name, byte[] value)
    throws JMSException
  {
    initializeWriting();
    getTable().put(name, value);
  }

  public void setBytes(String name, byte[] value, int offset, int length)
    throws JMSException
  {
    initializeWriting();
    byte[] data = new byte[length];
    System.arraycopy(value, offset, data, 0, length);
    getTable().put(name, data);
  }

  public void setObject(String name, Object value)
    throws JMSException
  {
    initializeWriting();
    if (((value instanceof Number)) || ((value instanceof String)) || ((value instanceof Boolean)) || ((value instanceof Byte)) || ((value instanceof Character)) || ((value instanceof byte[])))
    {
      getTable().put(name, value);
    }
    else
      throw new MessageFormatException(value.getClass() + " is not a primitive type");
  }

  protected void writeBody(DataOutput dataOut) throws IOException
  {
    super.writeMapProperties(this.theTable, dataOut);
    this.theTable = null;
  }

  protected void readBody(DataInput dataIn) throws IOException {
    this.theTable = super.readMapProperties(dataIn);
  }

  public boolean itemExists(String name)
    throws JMSException
  {
    return getTable().containsKey(name);
  }

  private void initializeWriting() throws MessageNotWriteableException {
    if (this.readOnlyMessage)
      throw new MessageNotWriteableException("This message is in read-only mode");
  }
}